import Ticket, { ITicket, TicketStatus, TicketPriority, TicketType } from '@database/models/Ticket';
import mongoose from 'mongoose';
import logger from '@utils/logger';

/**
 * 创建工单DTO
 */
export interface CreateTicketDto {
  title: string;
  description: string;
  type: TicketType;
  priority: TicketPriority;
  alertId?: string;
  createdBy: string;
  assignedTo?: string;
  tags?: string[];
}

/**
 * 更新工单DTO
 */
export interface UpdateTicketDto {
  title?: string;
  description?: string;
  priority?: TicketPriority;
  assignedTo?: string;
  tags?: string[];
}

/**
 * 工单查询过滤器
 */
export interface TicketFilter {
  status?: TicketStatus[];
  priority?: TicketPriority[];
  type?: TicketType[];
  assignedTo?: string;
  createdBy?: string;
  tags?: string[];
  search?: string;
}

/**
 * 工单服务类
 */
class TicketService {
  /**
   * 创建工单
   */
  async createTicket(dto: CreateTicketDto): Promise<ITicket> {
    try {
      const ticket = new Ticket({
        title: dto.title,
        description: dto.description,
        type: dto.type,
        priority: dto.priority,
        status: TicketStatus.OPEN,
        alertId: dto.alertId ? new mongoose.Types.ObjectId(dto.alertId) : undefined,
        createdBy: new mongoose.Types.ObjectId(dto.createdBy),
        assignedTo: dto.assignedTo ? new mongoose.Types.ObjectId(dto.assignedTo) : undefined,
        tags: dto.tags || [],
        watchers: [],
        comments: [],
        statusHistory: [],
      });

      // 设置 SLA 截止时间
      const now = new Date();
      const responseTime = this.getResponseTime(dto.priority);
      const resolutionTime = this.getResolutionTime(dto.priority);

      ticket.sla = {
        responseDeadline: new Date(now.getTime() + responseTime * 60 * 60 * 1000),
        resolutionDeadline: new Date(now.getTime() + resolutionTime * 60 * 60 * 1000),
        isBreached: false,
      };

      await ticket.save();
      logger.info(`Ticket created: ${ticket.ticketNumber}`);
      return ticket;
    } catch (error) {
      logger.error('Failed to create ticket:', error as Error);
      throw error;
    }
  }

  /**
   * 获取工单列表
   */
  async getTickets(
    filter: TicketFilter,
    page: number = 1,
    pageSize: number = 20
  ): Promise<{ tickets: ITicket[]; total: number }> {
    try {
      const query: any = {};

      // 状态筛选
      if (filter.status && filter.status.length > 0) {
        query.status = { $in: filter.status };
      }

      // 优先级筛选
      if (filter.priority && filter.priority.length > 0) {
        query.priority = { $in: filter.priority };
      }

      // 类型筛选
      if (filter.type && filter.type.length > 0) {
        query.type = { $in: filter.type };
      }

      // 负责人筛选
      if (filter.assignedTo) {
        query.assignedTo = new mongoose.Types.ObjectId(filter.assignedTo);
      }

      // 创建人筛选
      if (filter.createdBy) {
        query.createdBy = new mongoose.Types.ObjectId(filter.createdBy);
      }

      // 标签筛选
      if (filter.tags && filter.tags.length > 0) {
        query.tags = { $in: filter.tags };
      }

      // 搜索筛选
      if (filter.search) {
        query.$or = [
          { ticketNumber: { $regex: filter.search, $options: 'i' } },
          { title: { $regex: filter.search, $options: 'i' } },
          { description: { $regex: filter.search, $options: 'i' } },
        ];
      }

      const skip = (page - 1) * pageSize;

      const [tickets, total] = await Promise.all([
        Ticket.find(query)
          .sort({ createdAt: -1 })
          .skip(skip)
          .limit(pageSize)
          .populate('createdBy', 'username email')
          .populate('assignedTo', 'username email')
          .exec(),
        Ticket.countDocuments(query),
      ]);

      return { tickets, total };
    } catch (error) {
      logger.error('Failed to get tickets:', error as Error);
      throw error;
    }
  }

  /**
   * 获取工单详情
   */
  async getTicketById(ticketId: string): Promise<ITicket | null> {
    try {
      const ticket = await Ticket.findById(ticketId)
        .populate('createdBy', 'username email')
        .populate('assignedTo', 'username email')
        .populate('watchers', 'username email')
        .exec();

      return ticket;
    } catch (error) {
      logger.error(`Failed to get ticket ${ticketId}:`, error as Error);
      throw error;
    }
  }

  /**
   * 更新工单
   */
  async updateTicket(ticketId: string, dto: UpdateTicketDto): Promise<ITicket | null> {
    try {
      const ticket = await Ticket.findById(ticketId);
      if (!ticket) {
        return null;
      }

      if (dto.title !== undefined) ticket.title = dto.title;
      if (dto.description !== undefined) ticket.description = dto.description;
      if (dto.priority !== undefined) ticket.priority = dto.priority;
      if (dto.assignedTo !== undefined) {
        ticket.assignedTo = dto.assignedTo ? new mongoose.Types.ObjectId(dto.assignedTo) : undefined;
      }
      if (dto.tags !== undefined) ticket.tags = dto.tags;

      await ticket.save();
      logger.info(`Ticket updated: ${ticket.ticketNumber}`);
      return ticket;
    } catch (error) {
      logger.error(`Failed to update ticket ${ticketId}:`, error as Error);
      throw error;
    }
  }

  /**
   * 更新工单状态
   */
  async updateTicketStatus(
    ticketId: string,
    newStatus: TicketStatus,
    userId: string,
    userName: string,
    reason?: string
  ): Promise<ITicket | null> {
    try {
      const ticket = await Ticket.findById(ticketId);
      if (!ticket) {
        return null;
      }

      await ticket.updateStatus(
        newStatus,
        new mongoose.Types.ObjectId(userId),
        userName,
        reason
      );

      logger.info(`Ticket ${ticket.ticketNumber} status updated to ${newStatus}`);
      return ticket;
    } catch (error) {
      logger.error(`Failed to update ticket status ${ticketId}:`, error as Error);
      throw error;
    }
  }

  /**
   * 分配工单
   */
  async assignTicket(
    ticketId: string,
    assignedTo: string,
    userId: string,
    userName: string
  ): Promise<ITicket | null> {
    try {
      const ticket = await Ticket.findById(ticketId);
      if (!ticket) {
        return null;
      }

      await ticket.assign(
        new mongoose.Types.ObjectId(assignedTo),
        new mongoose.Types.ObjectId(userId),
        userName
      );

      logger.info(`Ticket ${ticket.ticketNumber} assigned to ${assignedTo}`);
      return ticket;
    } catch (error) {
      logger.error(`Failed to assign ticket ${ticketId}:`, error as Error);
      throw error;
    }
  }

  /**
   * 添加评论
   */
  async addComment(
    ticketId: string,
    userId: string,
    userName: string,
    content: string,
    isInternal: boolean = false
  ): Promise<ITicket | null> {
    try {
      const ticket = await Ticket.findById(ticketId);
      if (!ticket) {
        return null;
      }

      await ticket.addComment(
        new mongoose.Types.ObjectId(userId),
        userName,
        content,
        isInternal
      );

      logger.info(`Comment added to ticket ${ticket.ticketNumber}`);
      return ticket;
    } catch (error) {
      logger.error(`Failed to add comment to ticket ${ticketId}:`, error as Error);
      throw error;
    }
  }

  /**
   * 解决工单
   */
  async resolveTicket(
    ticketId: string,
    userId: string,
    userName: string,
    solution: string,
    rootCause?: string,
    preventiveMeasures?: string
  ): Promise<ITicket | null> {
    try {
      const ticket = await Ticket.findById(ticketId);
      if (!ticket) {
        return null;
      }

      ticket.resolution = {
        solution,
        resolvedBy: new mongoose.Types.ObjectId(userId),
        resolvedAt: new Date(),
        rootCause,
        preventiveMeasures,
      };

      await ticket.updateStatus(
        TicketStatus.RESOLVED,
        new mongoose.Types.ObjectId(userId),
        userName,
        '工单已解决'
      );

      logger.info(`Ticket ${ticket.ticketNumber} resolved`);
      return ticket;
    } catch (error) {
      logger.error(`Failed to resolve ticket ${ticketId}:`, error as Error);
      throw error;
    }
  }

  /**
   * 关闭工单
   */
  async closeTicket(
    ticketId: string,
    userId: string,
    userName: string
  ): Promise<ITicket | null> {
    try {
      const ticket = await Ticket.findById(ticketId);
      if (!ticket) {
        return null;
      }

      await ticket.updateStatus(
        TicketStatus.CLOSED,
        new mongoose.Types.ObjectId(userId),
        userName,
        '工单已关闭'
      );

      logger.info(`Ticket ${ticket.ticketNumber} closed`);
      return ticket;
    } catch (error) {
      logger.error(`Failed to close ticket ${ticketId}:`, error as Error);
      throw error;
    }
  }

  /**
   * 删除工单
   */
  async deleteTicket(ticketId: string): Promise<boolean> {
    try {
      const result = await Ticket.findByIdAndDelete(ticketId);
      if (result) {
        logger.info(`Ticket ${result.ticketNumber} deleted`);
        return true;
      }
      return false;
    } catch (error) {
      logger.error(`Failed to delete ticket ${ticketId}:`, error as Error);
      throw error;
    }
  }

  /**
   * 获取工单统计
   */
  async getTicketStatistics(filter?: TicketFilter): Promise<any> {
    try {
      const query: any = {};

      if (filter?.assignedTo) {
        query.assignedTo = new mongoose.Types.ObjectId(filter.assignedTo);
      }

      const [total, open, inProgress, pending, resolved, closed, byPriority, bySLA] =
        await Promise.all([
          Ticket.countDocuments(query),
          Ticket.countDocuments({ ...query, status: TicketStatus.OPEN }),
          Ticket.countDocuments({ ...query, status: TicketStatus.IN_PROGRESS }),
          Ticket.countDocuments({ ...query, status: TicketStatus.PENDING }),
          Ticket.countDocuments({ ...query, status: TicketStatus.RESOLVED }),
          Ticket.countDocuments({ ...query, status: TicketStatus.CLOSED }),
          Ticket.aggregate([
            { $match: query },
            { $group: { _id: '$priority', count: { $sum: 1 } } },
          ]),
          Ticket.countDocuments({ ...query, 'sla.isBreached': true }),
        ]);

      return {
        total,
        byStatus: {
          open,
          inProgress,
          pending,
          resolved,
          closed,
        },
        byPriority: {
          critical: byPriority.find((p: any) => p._id === TicketPriority.CRITICAL)?.count || 0,
          high: byPriority.find((p: any) => p._id === TicketPriority.HIGH)?.count || 0,
          medium: byPriority.find((p: any) => p._id === TicketPriority.MEDIUM)?.count || 0,
          low: byPriority.find((p: any) => p._id === TicketPriority.LOW)?.count || 0,
        },
        slaBreached: bySLA,
      };
    } catch (error) {
      logger.error('Failed to get ticket statistics:', error as Error);
      throw error;
    }
  }

  /**
   * 获取响应时间（小时）
   */
  private getResponseTime(priority: TicketPriority): number {
    switch (priority) {
      case TicketPriority.CRITICAL:
        return 1; // 1小时
      case TicketPriority.HIGH:
        return 4; // 4小时
      case TicketPriority.MEDIUM:
        return 8; // 8小时
      case TicketPriority.LOW:
        return 24; // 24小时
      default:
        return 8;
    }
  }

  /**
   * 获取解决时间（小时）
   */
  private getResolutionTime(priority: TicketPriority): number {
    switch (priority) {
      case TicketPriority.CRITICAL:
        return 4; // 4小时
      case TicketPriority.HIGH:
        return 24; // 24小时
      case TicketPriority.MEDIUM:
        return 72; // 72小时
      case TicketPriority.LOW:
        return 168; // 7天
      default:
        return 72;
    }
  }
}

export default new TicketService();
